<?php
/**
 * Created by PhpStorm.
 * User: 牛赞赞
 * Date: 2021/2/5
 * Time: 11:11
 */

namespace App\Task;

use App\Game\Conf\MainCmd;
use App\Game\Conf\SubCmd;
use App\Game\Core\Packet;
use App\Model\User;
use Psr\Container\ContainerInterface;
use Swoole\WebSocket\Server as WebSocketServer;

class OutRobotTimerTask
{
    /**
     * @var ContainerInterface
     */
    private $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function doOutRobot($account,$room_no){
        $game_conf  = config('game');
        $robot_conf = config('robot');
        $redis = redis();
        $room_wait_key  = sprintf($game_conf['user_room_wait'],$room_no);
        $room_chair_key = sprintf($game_conf['user_room_chair'],$room_no);
        $room_prepare_key = sprintf($game_conf['user_room_prepare'],$room_no);
        $out_robot_key = sprintf($robot_conf['user_room_outRobot'],$room_no);
        $room_map_key   = sprintf($game_conf['user_room'],$account);
        $fds = $this->getRoomFds($game_conf,$room_no);

        // 踢出等待房间机器人
        if($redis->exists($room_wait_key)){
            $waits = json_decode($redis->get($room_wait_key),true);
            if(!empty($waits)){
                $left_waits = array_values(array_diff($waits,[$account]));
                $redis->set($room_wait_key,json_encode($left_waits));
            }
        }

        // 踢出座位号机器人
        if($redis->exists($room_chair_key)){
            $chair_ids = json_decode($redis->get($room_chair_key),true);
            if(!empty($chair_ids)){
                foreach ($chair_ids as $k=>$v){
                    if(isset($chair_ids[$account])){
                        $chair_id = $chair_ids[$account];
                        unset($chair_ids[$account]);
                        // 房间广播
                        $this->roomBroadcast($chair_id,$fds);
                    }
                }
                $redis->set($room_chair_key,json_encode($chair_ids));
            }
        }

        // 踢出准备
        if($redis->exists($room_prepare_key)){
            $prepare_total = json_decode($redis->get($room_prepare_key),true);
            $prepare = array_values(array_diff($prepare_total,[$account]));
            $redis->set($room_prepare_key,json_encode($prepare));
        }

        // 踢出map
        if($redis->exists($room_map_key)){
            $room = $redis->get($room_map_key);
            if($room == $room_no){
                $redis->del($room_map_key);
            }
        }

        // 踢出集合
        if($redis->exists($out_robot_key)){
            $redis->sRem($out_robot_key,(string)$account);
        }

        // 世界广播
        $this->worldBroadcast();

        // 投递下一次机器人
        $task = container()->get(RobotAssignTask::class);
        $task->assignRobot($room_no);
    }


    /**
     * 世界广播
     */
    protected function worldBroadcast(){
        $serv = server();
        $hallData = $this->hallData();
        $data = Packet::packFormat('OK', 1, $hallData);
        $data = Packet::packEncode($data, MainCmd::CMD_SYS, SubCmd::SUB_GAME_HALL_RESP);
        foreach($serv->connections as $fd) {
            $client_info = $serv->getClientInfo($fd);
            $client[$fd] = $client_info;
            if(isset($client_info['websocket_status']) && $client_info['websocket_status'] == 3) {
                $serv->push($fd, $data, WEBSOCKET_OPCODE_BINARY);
            }
        }
    }

    /**
     * 房间广播
     * @param $chair_id
     * @param $fds
     */
    protected function roomBroadcast($chair_id,$fds){
        $serv = server();
        $msg    = ['status'=>'退出成功','chair_id'=>$chair_id];
        $data = Packet::packFormat('OK', 1, $msg);
        $room_data = Packet::packEncode($data, MainCmd::CMD_SYS, SubCmd::SUB_GAME_ROOM_QUIT_RESP);
        foreach($fds as $fd) {
            //获取客户端信息
            $client_info = $serv->getClientInfo($fd);
            $client[$fd] = $client_info;
            if(isset($client_info['websocket_status']) && $client_info['websocket_status'] == 3) {
                $serv->push($fd, $room_data, WEBSOCKET_OPCODE_BINARY);
            }
        }
    }

    /**
     * @param $game_conf
     * @param $room_no
     * @return array
     */
    protected function getRoomFds($game_conf,$room_no){
        $redis = redis();
        $room_wait_key = sprintf($game_conf['user_room_wait'],$room_no);
        $fds = [];
        if($redis->exists($room_wait_key)){
            $waits = json_decode($redis->get($room_wait_key),true);
            foreach ($waits as $v){
                $bind_key = sprintf($game_conf['user_bind_key'],$v);
                if($redis->exists($bind_key)){
                    $fds[] = $redis->get($bind_key);
                }
            }
        }
        return $fds;
    }

    /**
     * 游戏大厅房间数据
     * @return array
     */
    protected function hallData(){
        $game_conf = config('game');
        $room_total_key = $game_conf['user_room_total'];
        $fake_room_data = $this->fakeHallData();
        if(redis()->exists($room_total_key)){
            $rooms = redis()->sMembers($room_total_key);
            $hall_rooms = array();
            $hall_datas = array();
            $wait_room_conf = $game_conf['user_room_wait'];
            $room_data_conf = $game_conf['user_room_data'];
            foreach($rooms as $val){
                $wait_room_key = sprintf($wait_room_conf,$val);
                $room_data_key = sprintf($room_data_conf,$val);
                // 正在等待的房间
                if(redis()->exists($wait_room_key)){
                    $hall_rooms[$val] = json_decode(redis()->get($wait_room_key),true);
                }
                // 正在游戏的房间
                if(redis()->exists($room_data_key)){
                    $room_data = redis()->hGetAll($room_data_key);
                    if(!isset($room_data['is_game_over']) || ($room_data['is_game_over'] == 0)){
                        if(!empty($room_data['uinfo'])){
                            $wait_users = [];   // 正在等待房间里的用户account
                            $room_data_uinfo = json_decode($room_data['uinfo'],true);
                            foreach ($room_data_uinfo as $ks=>$vs){
                                $wait_users[] = $ks;
                            }
                            $hall_rooms[$val] = $wait_users;
                        }
                    }
                }
            }
            if(!empty($hall_rooms)){
                // 查询个房号用户信息
                $i = 0;
                foreach($hall_rooms as $k=>$v){
                    if(!empty($v)){
                        // 房间用户存在，查询用户信息
                        $curr_room_users = User::getUsers($v);
                        if($curr_room_users['code'] == 0){
                            $curr_room_data = $curr_room_users['data'];
                            foreach ($curr_room_data as $ks=>$vs){
                                $curr_room_data[$ks]['chair_id'] = $this->findChairId($k,$vs['account']);
                            }
                            $hall_datas[$i]['room_no']   = $k;
                            $hall_datas[$i]['room_data'] = $curr_room_data;
                        }
                        $i++;
                    }
                }
                $total_room_data = array_merge($fake_room_data,$hall_datas);
                return $total_room_data;
            }else{
                return $fake_room_data;
            }
        }else{
            return $fake_room_data;
        }
    }

    /**
     * 模拟大厅数据
     */
    protected function fakeHallData(){
        $game_conf = config('game');
        $fake_room_key = $game_conf['fake_room_hallFake'];
        $fake_expire = $game_conf['fake_expire'];
        if(redis()->exists($fake_room_key)){
            $fake_room_data = json_decode(redis()->get($fake_room_key),true);
            return $fake_room_data;
        }
        else{
            $num = rand(10000,99999);
            $data = User::getUserNum($num);
            $fake_room_data = [];
            $team_arr = array_chunk($data,3);
            $room_no = 9989;
            foreach($team_arr as $k=>$v){
                $team_data = [];
                if(!empty($v)){
                    foreach ($v as $kk=>$vv){
                        $team_data[] = [
                            'account'  => $vv['account'],
                            'score'    => $vv['score'],
                            'avatar'   => $vv['avatar'],
                            'chair_id' => (int)($kk+1),
                        ];
                    }
                }
                $fake_room_data[] = ['room_data'=>$team_data,'room_no'=>(int)($room_no+$k)];
            }
            // 缓存模拟房间数据
            redis()->set($fake_room_key,json_encode($fake_room_data,JSON_UNESCAPED_SLASHES));
            redis()->expire($fake_room_key,$fake_expire);
            return $fake_room_data;
        }
    }

    /**
     * 返回玩家房间桌位号
     * @param $room_no
     * @param $account
     * @return mixed
     */
    protected function findChairId($room_no,$account){
        $game_conf = config('game');
        $room_chair_key = sprintf($game_conf['user_room_chair'],$room_no);
        $chair_data = json_decode(redis()->get($room_chair_key),true);
        return $chair_data[$account];
    }
}